iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0
Software Development

從零打造網頁簡報編輯器系列 第 22 篇

Day 22|用 IndexedDB 保存文件、圖片與狀態

  • 分享至 

  • xImage
  •  

系列:一張投影片背後的工程:從零打造網頁簡報編輯器

對應程式版本:Git tag v0.4.0

版本說明:本文記錄第一版的本機資料庫、啟動還原與排隊自動儲存流程,並補充這一版讀取失敗時會覆蓋資料的問題與後續修正。

簡報文件是結構化資料,圖片卻是 Blob。全部塞進一段 JSON 會讓每次改一個字都重寫大型圖片;只保存圖片網址,重新整理後又可能找不到檔案。因此這一版用 IndexedDB 分開保存文件與圖片資產。

兩個 object store 各負責一件事

資料庫名稱是 web-slide-editor,版本為 1,第一次開啟時建立兩個 object store:

const PRESENTATIONS_STORE = 'presentations'
const ASSETS_STORE = 'assets'
const ACTIVE_PRESENTATION_ID = 'active'

presentations 保存目前文件與更新時間;assets 以資產 ID 保存 Blob、MIME、檔名、原始寬高與建立時間。文件中的圖片物件只保留 assetId,因此文字修改不必複製圖片內容。

https://ithelp.ithome.com.tw/upload/images/20261002/20182759axdzhEOAuY.png

需要一起匯入文件與圖片時,saveProject 會開啟涵蓋兩個 object store 的同一筆 readwrite transaction。任一寫入失敗,整筆交易便不會留下半套專案。

先還原,再允許自動儲存

程式啟動後先呼叫 loadPresentation(),等讀取結束才把 hydrated 設為 true;自動儲存要等 hydrated 為 true 才會開始計時。這個順序很重要,否則初始空白文件可能在舊文件讀完前先被自動儲存覆蓋。

文件變更後等待 400 毫秒再寫入,連續操作會取消前一個計時器。真正的寫入還會排進同一條 Promise queue,避免較慢的舊存檔在較新的版本之後才完成。revision 編號只負責讓畫面上的「已儲存」狀態對應最新一次請求。

不過這一版只擋住讀取成功與沒有舊資料兩種情況:讀取失敗的 catch 同樣會把 hydrated 設為 true。loadPresentation() 會用 isPresentationDocument 驗證讀到的文件,一旦驗證失敗,例如平均分布把較寬的物件推到畫布外、x 變成負數,畫面就停在初始空白文件;400 毫秒後自動儲存用它蓋掉原本的資料,畫面上的儲存狀態最後還會顯示「已儲存在這台裝置」。後來的修正(commit 4bd1dbd)從三處補上:平均分布不再把物件推出選取範圍;寫入前先驗證文件,讀不回來的內容不會存進去;讀取失敗時暫停自動儲存並保留原資料,直到使用者匯入備份。

用完整往返驗證 Blob

儲存測試建立一個含圖片的文件,分別寫入文件與 PNG Blob,再重新讀取兩者。測試除了比較文件,也確認資產檔名、尺寸與 Blob 大小;另一個案例則驗證 saveProject 能在一次操作中保存匯入文件與資產。

這些資料保存在目前瀏覽器設定檔,不是雲端同步。重新整理或重新開機後仍可讀取,但清除網站資料、更換瀏覽器或裝置時不會自動帶走,因此下一步仍需要可下載的專案備份。

參考資料


上一篇
Day 21|復原重做如何記住一次完整操作
系列文
從零打造網頁簡報編輯器 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言